home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / REFERENC / TPR / TPR3A.TXT < prev    next >
Text File  |  1992-10-19  |  60KB  |  1,461 lines

  1.                                    Chapter 3
  2.                  - Part 1 of 3 parts -
  3.                                     of the
  4.                             Turbo Pascal Reference
  5.  
  6.                            The Turbo Pascal Language
  7.  
  8.  
  9. This chapter is part of the Turbo Pascal Reference electronic freeware book (C)
  10. Copyright 1992 by Ed Mitchell.  This freeware book contains supplementary
  11. material to Borland Pascal Developer's Guide, published by Que Corporation,
  12. 1992.  However, Que Corporation has no affiliation with nor responsibility for
  13. the content of this free book.  Please see Chapter 1 of the Turbo Pascal
  14. Reference for important information about your right to distribute and use this
  15. material freely.  If you find this material of use, I would appreciate your
  16. purchase of one my books, such as the Borland Pascal Developer's Guide or
  17. Secrets of the Borland C++ Masters, Sams Books, 1992.  Thank you.
  18.  
  19. Note:  For ease of access, Chapter 3 is continued in TPR3B.TXT and TPR3C.TXT.
  20.  
  21.  
  22.      The Pascal programming language was originally developed by Niklaus Wirth
  23. as an idealized language for teaching basic concepts of programming.  Many of
  24. the concepts and constructions used in Pascal trace their ancestry to the Algol
  25. programming language developed in the early 1960's.  By 1968, Wirth had
  26. developed the basic structure of Pascal, but it was not until his publication
  27. of the Pascal User Manual and Report in 1973 that Pascal received wide spread
  28. acceptance.
  29.      Since that time, the core structure of Pascal has remained largely the
  30. same, but many signficant enhancements have been made, especially in the
  31. version known as Turbo Pascal.  These enhancements include:
  32.  
  33.        Units, for the sharing and reuse of code, 
  34.  
  35.        Powerful object oriented programming capabilities,
  36.  
  37.        Extensive library support including graphics, overlays (for managing
  38.        large programs), and system-level access for system programming.
  39.  
  40.      Yet, because Turbo Pascal traces its heritage to Pascal's early
  41. development as a tool for teaching programming, Turbo Pascal is probably the
  42. premier programming language for learning modern programming concepts and
  43. practices.  And with Borland's significant enhancements, Turbo Pascal has
  44. become the definitive implementation of the Pascal language, providing  one of
  45. the most powerful development languages and environments available.  The
  46. professional editions of Turbo Pascal and Borland Pascal are every bit as
  47. powerful as C++, plus Borland's Pascal compilers generate fast, compact code,
  48. often much smaller than similar C++ code.  Except for Pascal's lack of
  49. templates and overloaded functions, Turbo Pascal has all the features and
  50. capabilities of C++.
  51.      This chapter presents an overview of the entire Turbo Pascal language,
  52. except for object oriented programming (OOP) features.  OOP may be found in
  53. Chapter 4, "Object Oriented Programming" in the Borland Pascal Developer's
  54. Guide.
  55.  
  56.  
  57. Your First Turbo Pascal Program
  58.      Common practice is to introduce a new programming language by writing a
  59. simple program that simply displays,
  60.  
  61.      Hello, World!
  62.  
  63. In Turbo Pascal, such a program look liks this:
  64.  
  65.      program Hello;
  66.      begin
  67.           Writeln('Hello, World!');
  68.      end.
  69.  
  70. Each Pascal program begins with a statement containing the keyword program and
  71. the program name, shown here as Hello, optional variable declarations (none
  72. shown in this example), the keyword begin, zero or more Pascal statements, and
  73. an end statement to terminate the program.  Each statement is terminated with a
  74. semicolon, except the last end statement is terminated in a period.
  75.      The statement,
  76.  
  77.      Writeln('Hello, World!');
  78.  
  79. calls a built-in Pascal routine called Writeln, which has as its single
  80. parameter, the contents of the text to be printed.
  81.      All Pascal programs have roughly the same structure as that used by the
  82. Hello program, but with many more options available.
  83.      While the Turbo Pascal Reference includes substantial tutorial and
  84. reference information, if you have little or no programming experience, I
  85. suggest you consult an introductory text first.
  86.      Programmers who are experienced in Pascal or other programming languages
  87. such as C, QuickBasic or Visual Basic, will find that Turbo Pascal Reference
  88. provides a concise and complete description of the Turbo Pascal language,
  89. libraries, development environment and the powerful Turbo Vision
  90. character-based windowing system.
  91.  
  92.  
  93. Pascal Program Structure
  94.      Each Pascal program is organized in a standard format, as shown in figure
  95. 3.1.  Turbo Pascal, unlike other implementations of Pascal, does not require
  96. the strict ordering of declarations suggested by figure 3.1.  In Turbo Pascal,
  97. you can, if you wish, place type declarations before the const declarations, or
  98. even add a second var section after you have defined procedures and functions. 
  99. You do not need to have each of the declarations sections shown, but only those
  100. that are used by your program.  Figure 3.2 displays a "railroad" syntax diagram
  101. illustrating how the declarations may occur in any order.  These syntax
  102. diagrams are frequently used to describe the structure of Pascal programs.  You
  103. read the diagram by starting, usually, at the upper left corner and tracing
  104. through the drawing, through each keyword or symbol in the language, until you
  105. exit the diagram, usually a the upper right.
  106.  
  107. Figure 3.1.  The structure of Pascal program.
  108.  
  109.      program programname;
  110.      uses
  111.        unitnames-list;
  112.      label
  113.        declarations;
  114.      const
  115.        declarations;
  116.      type
  117.        declarations;
  118.      var 
  119.        variable declarations;
  120.      procedure and function declarations;
  121.  
  122.      begin
  123.        Main body of program;
  124.      end.
  125.  
  126. ***03tpr02.pcx***
  127. Figure 3.2.  A syntax diagram showing how the elements of the Pascal language
  128. declarations may appear in any order.
  129.  
  130.  
  131. Pascal Data Types
  132.      Data types determine the type of data and the permissible range of values
  133. within each type upon which Pascal can operate.   These data types range from a
  134. variety of small and large integer values to several real or floating point
  135. number formats, plus character and string values.  The basic data types of
  136. Pascal are shown in Table 3.1.
  137.      For reasons of program efficiency, some values may be represented by more
  138. than one type.  Consider a numeric value in the range of 0 to 100.  Such a
  139. value can be represented by an Integer, Byte, Shortint, Longint or other
  140. standard types.    These values vary in the amount of memory storage they
  141. require, and hence, the length of time it takes the CPU to process such data. 
  142. For example, the Byte data type uses 8 bits of memory, while the Longint type
  143. takes 32 bits.  
  144.      Table 3.1 presents the standard predefined Turbo Pascal data types.  As
  145. described later in this chapter, you may also create custom data types, as
  146. appropriate.
  147.  
  148.  
  149. Table 3.1.  The standard Pascal data types.
  150. Data Type          Typical Values              Size and Description
  151.  
  152. Boolean  True, False         1 byte
  153.           A Boolean value holds one of the predefined constants True or False,
  154.           where Ord(True) = 1 and Ord(False) = 0.
  155.  
  156. Byte     0 to +255           1 byte
  157.           A Byte value is an integer in the range of 0 to +255 and is
  158.           represented in an unsiged 8 bit format.
  159.  
  160. Shortint -128 to +127        1 byte
  161.           A numeric value in the range -128 to +127 is a signed 8-bit value
  162.           called a Shortint.
  163.  
  164. Integer  -32768 to +32767    2 bytes
  165.           Integers store numeric values in the range of -32768 to +32767 in
  166.           signed 16 bit format.  
  167.  
  168. Word     0 to 65535          2 bytes
  169.           The Word data type is an unsigned 16 bit value and is used when
  170.           numbers larger than standard integers are required, and when negative
  171.           values are not needed.
  172.  
  173. Longint  -2147483648 to 2147483647  4 bytes
  174.           Longints store signed 32-bit values and are used for storing very
  175.           large integer values.  They may also be used for high speed fixed
  176.           point operations for small values having a presumed decimal point. 
  177.           This requires that you write appropriate routines for entering and
  178.           displaying such fixed point values.  Also see the Comp data type.
  179.  
  180. Real     2.9 x 10-39 to 1.7 x 1038             6 bytes
  181.           Real values hold positive and negative floating point numbers in the
  182.           range shown, providing 11 to 12 digits of accuracy.  Real numbers are
  183.           written as a sequence of digits, a decimal point, and additional
  184.           digits to specific the fractional part, if needed.  Reals may be also
  185.           be written using exponential notation, such as 1E2 meaning 1 X 102.
  186.  
  187. Single   1.5 x 1045 to 3.4 x 1038              4 bytes
  188.           $N+, $E+ required for use.  Provides 7 to 8 digit real number
  189.           accuracy in an IEEE  floating point format, compatibile with the 8087
  190.           math coprocessor.
  191.  
  192. Double   5.0 x 10-324 to 1.7 x 10308           8 bytes                         
  193.  
  194.           $N+, $E+ required for use.  Provides 15 to 16 digit real number
  195.           accuracy in an IEEE floating point format compatible with the 8087
  196.           math coprocessor.
  197.  
  198. Extended 3.4 x 10-4932 to 1.1 x 104932         10 bytes
  199.           $N+, $E+ required for use.  Provides 19 to 20 digits of accuracy for
  200.           floating point values.
  201.  
  202. Comp     -263+1 to 263-1     8 bytes
  203.           $N+, $E+ required for use.  Provides 19 to 20 digits of accuracy in a
  204.           64 bit Longint-type.  The values range from -9.2 x 1018 to 9.2 x
  205.           1018.  Comp types are used for integer values only, but are
  206.           implemented in the math coprocessor and the 8087 floating point
  207.           software emulation routines.
  208.  
  209. Char     ASCII 0 to 255      1 byte
  210.           Stores character values represented by their internal ASCII code. 
  211.           Character constants are written between single quotes as 'x', where x
  212.           may be replaced by any valid character.  For non-printable
  213.           characters, you may use the special notation #nn to directly specify
  214.           the ASCII value of the desired character.  For example, the Enter key
  215.           on the keyboard generates an ASCII 13 "carriage return" code.  You
  216.           can assign such a value by writing,
  217.          EnterKey := #13;
  218.  
  219. String   2 to 256 bytes total size
  220.           A string contains a string of characters, such as 'ABCDEF', which is
  221.           a string constant of 6 bytes in length, plus a length byte that
  222.           always appears as the invisible first byte of a string.  Strings are
  223.           stored as an array of Char, where the zero'th element contains the
  224.           length of the string, in bytes, and the subsequent bytes contains the
  225.           string contents.  A string identifier is declared using the String
  226.           data type, which allocates a length byte, plus 255 bytes for the
  227.           actual text.  A shorter string allocation may be specified by writing
  228.           String[n] where n represents the maximum defined length of the
  229.           string.  This is explained in greater detail, later in this chapter. 
  230.           To use the single quote character within a string, use two quotes.  
  231.           Hence, by writing 'ABC''DEF' you effectively insert a single quote
  232.           between C and D.
  233.  
  234.  
  235. Writing Integer, Word and Byte constants
  236.          Integer and byte constants may be written in decimal notation, such as
  237. 255, or in hexadecimal notation, such as $FF.  Hexadecimal values are always
  238. preceded by a $ symbol and immediately followed by valid hexadecimal digits,
  239. which are 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, and F.
  240.  
  241.  
  242. A Note on the Use of Floating Point Values
  243.      The compiler directives, $N, controlling code generation for a math
  244. coprocessor (either the 8087, 80287 or 80387), and $E, controlling 8087
  245. software emulation, are set such that only the Real numeric type is initially
  246. available for floating point arithmetic, and all floating point arithmetic is
  247. performed with software run-time library routines.  (Compiler directives
  248. specifying specific compiler options are placed within source code comments,
  249. like {$N+}.  
  250.      To gain access to the additional floating point types (Single, Double,
  251. Extended and Comp), you should compile your program using the {$N+, E+} option.
  252. This generates floating point code that will operate on systems with or without
  253. a math coprocessor.  If the math coprocessor is present, it will be used.  If
  254. the math coprocessor is not found, then the 8087 will be simulated in software.
  255. This has the advantage that your programs will run on all configurations, but
  256. has the disadvantage that the software emulation routines take a substantial
  257. amount of memory (about 10k more code space) and run slower than the standard
  258. library that is linked when the $E- option is in effect).
  259.      If your program does not require use of a math coprocessor (either the
  260. 8087, 80287 or 80387), you should use the Real numeric type for floating point
  261. arithmetic and compile with the {$N-, E-} options set.  This format provides a
  262. good compromise among number of digits of accuracy, memory storage, speed of
  263. software implementation and code size. 
  264.      However, if your application makes use of extensive floating point
  265. operations and will either definitely have a math coprocessor available or is
  266. likely to have a math coprocessor available, or must operate in an IEEE
  267. standard mode for purposes of data exchange, then the other data types may be
  268. used.  To use the other data types (Single, Double, Extended or Comp) requires
  269. that you set the $N and $E options as {$N+, E+}.
  270.  
  271.  
  272. Declaring Identifiers
  273.      Every identifier used in a Turbo Pascal program must be declared or
  274. defined either as part of the main program section or within defined procedures
  275. and functions.  If you are coming to Turbo Pascal with a background in BASIC
  276. programming, this may seem a bit peculiar since BASIC allows you to use any
  277. variable name by assigning a value to it.  Pascal requires that you define a
  278. list of identifier names before they are used in the program. Identifiers can
  279. be defined as variables, constants, programmer defined types and several other
  280. variants.
  281.      A global identifier is one which is visible to all procedures and
  282. functions within the program unit and is defined in a program-level var
  283. declaration.  A local identifier is one that is visible only within the
  284. procedure or function where it is defined.  This characteristic of an identifer
  285. - either global or local - is called the identifier's scope.
  286.      An identifier must begin with a letter or an underscore character (_), and
  287. may then contain combinations of lower and upper case letters, digits and
  288. underscores.  Some examples,
  289.  
  290.      A,   Alpha,       _LinkRef    Pointer_to_Names
  291.      X10  Alpha35      C01234      X_12
  292.  
  293. Identifiers are not case sensitive, meaning that abc and ABC refer to the same
  294. identifier.  The Turbo Pascal compiler retains up to the first 63 characters of
  295. identifiers, and any excess characters are disgarded.  Identifiers can be any
  296. valid sequence of characters, letters and underscores, except for the Turbo
  297. Pascal keywords shown in Table 3.2.  These keywords are reserved for use by the
  298. Turbo Pascal language and will cause compiler errors if you attempt to use a
  299. reserved word for an identifier.
  300.  
  301.  
  302. Table 3.2.  Table of Turbo Pascal Keywords.
  303. These keywords are reserved for use by the Turbo Pascal language and may not be
  304. used as identifiers.
  305.  
  306. and          end               nil         shr
  307. asm          file              not         string
  308. array        for               object      then
  309. begin        function          of          to
  310. case         goto              or          type
  311. const        if                packed      unit
  312. constructor  implementation    procedure   until
  313. destructor   in                program     uses
  314. div          inline            record      var
  315. do           interface         repeat      while
  316. downto       label             set         with
  317. else         mod               shl         xor
  318.  
  319. These keywords are reserved by Turbo Pascal but may be redefined in your
  320. programs although its not recommended that you do so.
  321.  
  322. absolute  external     forward     near
  323. assembler far          interrupt   private
  324. virtual                            
  325.  
  326.           The keyword private is a reserved word only within the scope of an
  327. object definition.  Object oriented programming is covered in depth in Chapter
  328. 4, "Object Oriented Programming" of the Borland Pascal Developer's Guide (Que
  329. Corp, 1992).
  330.           As their names imply, a variable holds a value that can change during
  331. program execution; a constant holds a value that remains the same during
  332. program execution; and a type is a user defined type, especially useful for
  333. creating record structures, arrays and objects (these concepts are explained at
  334. the end of this chapter).
  335.      Within a given scope, you can have only one identifier with the same name.
  336. A program can define only one variable called X, although it can later define
  337. another variable X provided that the identifier is defined in a different scope
  338. - such as locally within a procedure, function or within a separate unit
  339. (described in Chapter 2, "Units and Dynamic Link Libraries" of the Borland
  340. Pascal Developer's Guide).
  341.  
  342.  
  343. Constants
  344.      A constant identifier is declared using the const statement, and is
  345. followed by as many constant declarations as are needed in the program.  Here
  346. is an example declaring 4 constant identifiers, an integer, a string, and two
  347. characters:
  348.  
  349.      const
  350.           MaximumSize = 100;
  351.           DefaultName = 'SAMPLE.TXT';
  352.           ExitCommand = 'Q';
  353.           EnterKey = #13;
  354.  
  355. The notation #13 assigns the ASCII code 13 to the character identifier
  356. EnterKey.
  357.      Constant identifiers may be used anywhere in your Pascal program that a
  358. number, a string or a character or other appropriate data type is used. 
  359. Constants are often used to set values that might be changed at a later date,
  360. but which do not need to be stored in a variable because they never change
  361. during program execution.  For example, MaximumSize might be set to 100 data
  362. records initially, but perhaps a new, larger hard disk makes more storage
  363. available.  With the increased storage you might revise MaximumSize up, perhaps
  364. to 1000.  Rather than search through all the Pascal source looking for 1000,
  365. you need only change the value assigned to MaximumSize where it is defined.
  366.      Some examples that use constants:
  367.  
  368. const
  369.      MaximumSize = 100;
  370. var
  371.      InfoTable : Array[0..MaximumSize] of Integer;
  372.      ...
  373.      for  I := 0 to MaximumSize do InfoTable[I] := 0;
  374.  
  375.      A special type of constant, called a typed constant provides a way to
  376. initialize variables when they are declared, rather than through an assignment
  377. statement.   Such a constant is actually a variable that is initialized to some
  378. starting value and can be assigned new values, just like a variable.  Typed
  379. constants are described below under the heading Typed constants:  Initializing
  380. Variables.
  381.  
  382. Variables
  383.      Variables are defined in the var section of the Pascal program, preceded
  384. by the keyword var, and followed by any number of variable declarations,
  385. separated by semicolons.  For example,
  386.  
  387.      var
  388.        TotalLines : Word;
  389.        InputLine : String[128];
  390.        R : Real;
  391.        AllDone : Boolean;
  392.  
  393. The InputLine variable is a string declared to hold a maximum of 128
  394. characters.  The total amount of memory occupied by InputLine is 129 bytes,
  395. including the length byte.
  396.  
  397. Important note:  Uninitialized variables
  398.      The value of a declared variable is undefined until your program
  399. explicitly assigns a value to the variable with an assignment statement.  A
  400. common Turbo Pascal programming error is to use an uninitialized variable
  401. without realizing that its value is potentially random.  Such programs may run
  402. fine and then suddenly fail without warning.  Always insure that you have
  403. assigned a value to your variables prior to using the variable in an
  404. expression.
  405.      In some instances, you may be able to give your variables an initial value
  406. as part of the declaration.  See Typed Constants:  Initializing Variables,
  407. below.
  408.  
  409.  
  410. Arrays
  411.      An array holds a specific number of items, all the same type.  For
  412. example,
  413.  
  414.      var
  415.        Sizes : Array[0..9] of Integer;
  416.  
  417. defines Sizes to be an array having 10 integer elements.  The values in the
  418. array are accessed by indexing into the array, so that Size[0] references the
  419. first element and Size[9] references the last element.  The minimum and maximum
  420. array bounds are determined by the array index type.  By writing,
  421.  
  422.      var
  423.        Sizes : Array [1..10] of Integer;
  424.  
  425. you also define an array of 10 elements, indexed beginning at 1.  You may also
  426. write,
  427.  
  428.      var
  429.        Sizes : Array[-5..4] of Integer;
  430.  
  431. which also creates a 10 element array, now indexed from -5 to +4.  In general
  432. though,, it is more efficient to begin arrays at 0 since it takes less
  433. generated code to access each element.
  434.      The array index may be specified with one of the following data types:
  435.  
  436.      Boolean, Byte, Shortint, Integer, Word, Char
  437.  
  438. As a practical matter, you must use a subrange of Integer or Word, as the array
  439. would otherwise be to large for Turbo Pascal to create.  For example,
  440.  
  441.      var
  442.        Sizes : Array[Byte] of Integer;
  443.  
  444. effectively creates Sizes as an array of 0 to 255 elements.  When an array is
  445. defined using a data type, the acceptable values for the array index are the
  446. same as the data values defined for the data type.  Listing 3.1 illustrates
  447. array indexing using Char and Boolean array types.  Note how the Charray is
  448. indexed using the character value 'a'.
  449.  
  450.  
  451. Listing 3.1.  Example using arrays of non-integer types.
  452.  
  453. program Demo;
  454. var
  455.   Charray : array[Char] of Integer;
  456.   B : array[Boolean] of Integer;
  457. begin
  458.   Charray['a']:= 33;
  459.   B[false] := 0;
  460. end.
  461.  
  462.  
  463. Multidimensional arrays
  464.      Multi-dimensional arrays are created by specifying each additional
  465. dimension after a comma, in the array declaration:
  466.  
  467.      var
  468.        Sizes : Array[0..5, 0..9] of Integer;
  469.  
  470. defines a two-dimensional array 6 x 10 in size.  Alternatively, you can write:
  471.  
  472.      var
  473.        Sizes : Array[0..5] of Array[0..9] of Integer;
  474.  
  475. Both notations produce identical array definitions.  
  476.      The elements of a multi-dimensional array are accessed using the
  477. appropriate number of indices, such as Sizes[0,9] or Sizes[5,3].
  478.  
  479. Important note:  Maximum array sizes
  480.      The maximum allowed number of dimensions is limited only by available
  481. memory and the restriction that the largest Pascal data structure is limited to
  482. 65,521 bytes in total memory storage.  The 65,521 byte restriction also applies
  483. to single dimension arrays.
  484.  
  485.  
  486. Arrays and the Packed Keyword
  487.      Array definitions may be prefaced by the keyword packed for compatability
  488. with other versions of Pascal.  Packing causes the compiler to minimize the
  489. amount of space required by an array, even if doing so would result in
  490. increased code generation or slower array access.  For example, some compilers
  491. may store an array of bytes, with each byte in separate 16-bit memory words. 
  492. The packed option causes the compiler to insure that bytes are stored in byte
  493. values, not words.  In the case of Turbo Pascal, packing occurs automatically
  494. and the packed keyword is ignored.
  495.  
  496.  
  497. Types
  498. Syntax:
  499.      type <identifier> = <type definition>
  500.  
  501. Examples:type
  502.      TNewInt = Integer;
  503.      TTableEntry = String[80];
  504.      TShortString = String[10];
  505.      TTable = Array[MinSize..MaxSize] of TTableEntry;
  506.      ...
  507. var
  508.      Table : TTable; { becomes an array of TTableEntry,
  509.                     a.k.a. String[80], as defined }
  510.      X : TNewInt; { is a new special purpose integer type }
  511.  
  512. Description:
  513.      In addition to Turbo Pascal's predefined data types, the Pascal language
  514. contains a means for creating user defined data types.  The type keyword
  515. precedes a list of one or more type definitions.  While a type identifier, like
  516. variable and constant identifiers, may contain alphabetic, numeric and the
  517. underscore characters, many Pascal programmers have adopted a convention of
  518. beginning a type identifier with the letter T to help make their source code
  519. more readable.  The examples above all use this convention.
  520.      An important use of type is in creating data types for use as parameters
  521. in procedures and functions (described later in this chapter).  Procedural
  522. parameters may only specify a simple type declaration - and cannot specify an
  523. array declaration, for instance.  In order to pass an array to a procedure, a
  524. new type, such as TTable in the example above, must be created, and is then
  525. used as the type of the procedure parameter.
  526.      Types are also used to declare pointers to data types (pointers are
  527. described later in this chapter).
  528.      Many examples of type declarations appear throughout the remainder of this
  529. chapter, and throughout many examples in this book.
  530.  
  531.  
  532. Enumerated Types
  533.      Enumerated types provide for a specific list of constant values.  For
  534. example, 
  535.  
  536. type 
  537.      TDaysOfTheWeek = (Sun, Mon, Tue, Wed, Thu, Fri, Sat, Sun);
  538.  
  539. creates a new type called TDaysOfTheWeek, which consists of an enumerated list
  540. of values that may be used in expressions.  For example,
  541.  
  542.      var
  543.        DayInformation : TDaysOfTheWeek;
  544.      ...
  545.      DayInformation := Mon;
  546.  
  547. The data type for DayInformation is TDaysOfTheWeek, so it should only be
  548. assigned values from the predeclared list of enumerated identifiers.
  549.      An enumerated type is essentially equivalent to a list of constant values,
  550. with the first item in the list having the value of zero, and the subsequent
  551. enumerated identifiers being assigned the next succeeding value.  For
  552. TDaysOfTheWeek, the list of values are equivalent to the const declaration,
  553.  
  554.      const
  555.        Sun = 0;
  556.        Mon = 1;
  557.        Tue = 2;
  558.        Wed = 3;
  559.        Thu = 4;
  560.        Fri = 5;
  561.        Sat = 6;
  562.  
  563. As can be seen, the values of the enumerated identifiers are determined by the
  564. order that they appear within the enumerated list.
  565.      The enumerated type may be used like other scalar types, such as Integer,
  566. and may be compared using any of the standard relational operators.  The
  567. enumerated type may be used anywhere a scalar type is used, as in, for example,
  568. a for loop using a loop control variable declared as TDaysOfTheWeek:
  569.  
  570.      var
  571.        Day : TDaysOfTheWeek;
  572.      ...
  573.      for Day := Sun to Sat do ...
  574.  
  575. If the function Succ() is applied to an enumerated type, Succ() returns the
  576. next element in the list, so that Succ(Tue) returns Wed.
  577.      The standard Pascal data type, Boolean, is itself an enumerated type,
  578. declared as,
  579.  
  580.      type
  581.        Boolean = (False, True);
  582.  
  583. Important note:  Enumerated Types versus Scalar types
  584.      The original Pascal definition, and some other versions of Pascal, use the
  585. terminology scalar type (having enumerated values), in place of enumerated
  586. type.
  587.  
  588.  
  589. Subrange Types
  590.      A new type, defined as a subrange of any existing scalar type is easily
  591. defined with the subrange notation:
  592.  
  593.      var
  594.        IndexValues : 1..100;
  595.  
  596. where 1..100 means that the variable IndexValues will hold values in the range
  597. of 1 to 100.
  598.      You can create a user defined subrange type by writing a type definition
  599. as in this example,
  600.  
  601.      type TIndexRange = 1..100;
  602.  
  603. And then defining subsequent variables as,
  604.  
  605.      var
  606.        A, B : TIndexRange;
  607.  
  608. Another example is creating a subrange of characters, as in this example,
  609.  
  610.      type
  611.        LowerCase = 'a'..'z';
  612.        UpperCase = 'A'..'Z';
  613.  
  614.      Enumerated types may also be written as a subrange.  For instance, with
  615. TDaysOfTheWeek defined as,
  616.  
  617.      type TDaysOfTheWeek = (Sun, Mon, Tue, Wed, Thu, Fri, Sat, Sun);
  618. a subrange of TDaysOfTheWeek can be defined as,
  619.      var
  620.        WeekDays : Mon..Fri;
  621.  
  622.  
  623. Sets
  624. Syntax:
  625.      set of <type>
  626.  
  627. Description:
  628.      A set defines a collection of values.  Using the TDaysOfTheWeek type
  629. described above, you can create a set by writing,
  630.  
  631.      var
  632.        WeekSet : Set of TDaysOfTheWeek;
  633.  
  634. This creates WeekSet to contain from zero up to 7 elements from the list of the
  635. values defined for TDaysOfTheWeek.  For example, to assign a range of values to
  636. WeekSet, you may write,
  637.  
  638.      WeekSet := [Sun..Wed];
  639.  
  640. or, explicity list each of the desired values in the set, such as,
  641.  
  642.      WeekSet := [Sun, Mon, Tue, Wed];
  643.  
  644. After giving WeekSet some values, you can check for a specific element using
  645. the in set operator.  For example,
  646.  
  647.      if Sun in WeekSet then
  648.        Writeln('Sunday is active.');
  649.  
  650.      A convenient use for sets is to check for a value appearing within a
  651. range.  For instance, to determine if a character value is a lower case letter,
  652. where Ch is of type Char, you may write, 
  653.  
  654.      if (Ch >= 'a') and (Ch <= 'z') then
  655.        Writeln( Ch,' is a lower case letter.');
  656.  
  657. Or, using set notation, you can write,
  658.  
  659.      if Ch in ['a'..'z'] then
  660.        Writeln( Ch, ' is a lower case letter.');
  661.  
  662. You may also use set notation to check for a variety of values, as in this
  663. example:
  664.  
  665.      if Ch in ['0'..'9', 'A'..'Z', 'a'..'z'] then ...
  666.  
  667. Sets provide an easy to use method of checking for membership among a large
  668. group of values.  By using the in operator on a set, you can reduce a
  669. complicated if-then statement containing many and plus or boolean operators,
  670. into a simple test.
  671.      The null set is written as [] and can be used to initialize a set.
  672.  
  673.  
  674. Set Relational Operators
  675.      Four relational comparisons are permitted on sets.
  676.  
  677.        A = B : Compares two sets and returns True only if A and B contain the
  678.        same members.  Example:  [Sun, Tue, Fri] = [Tue, Fri, Sun] returns True.
  679.  
  680.        A <> B: Compares two sets and returns True if A and B do not contain the
  681.        same members.
  682.  
  683.        A <= B : Determines if A is a subset of B.  Example:  If A contains
  684.        [Sun, Mon, Tue] and B contains [Sun, Mon, Tue, Wed, Thu], then A is a
  685.        subset of B and the expression is True.
  686.  
  687.        A >= B : Determines if A is a superset of B, meaning that A contains the
  688.        subset described by B.  Example:  If  A contains [Sun..Sat], and B
  689.        contains [Mon..Fri], then A >= B is True.
  690.  
  691.  
  692. Set Logical Operators
  693.      Three logical operations may be performed on sets.
  694.  
  695.        + or Union:  [Sun, Mon, Tue, Wed] + [Mon, Thu, Fri] produces the result
  696.        [Sun, Mon, Tue, Wed, Thu, Fri], effectively combining the two sets
  697.        together.
  698.  
  699.        -  or Difference:  [Sun, Mon, Tue, Wed] - [Mon, Tue, Fri] produces the
  700.        result [Sun, Tue, Wed], which is the set of elements of the first set
  701.        that are not also in the second set.
  702.  
  703.        * or Intersection: [Sun, Mon, Tue, Wed] * [Mon, Tue, Fri] returns [Mon,
  704.        Tue], which are the set elements that appear in both sets.
  705.  
  706.  
  707. Records
  708.      A record specifies a collection of data.  Typically, a record data type is
  709. used to store related information.  For example,
  710.  
  711.      var
  712.        PersonInfo = record
  713.           Name : String[30];
  714.           StreetAddress : String[30];
  715.           City : String[20];
  716.           State : String[2];
  717.           Zip : String[9];
  718.        end;
  719.  
  720. This record declaration defines a new variable PersonInfo, containing five
  721. separate data fields.  The fields of a record are accessed individually using
  722. both the variable name and the field name, together.  For example,
  723.  
  724.      PersonInfo.Name := 'Sam Bedford';
  725.      PersonInfo.Zip := '98327-7463';
  726.  
  727. Records may be defined inside other records.  For example,
  728.  
  729.      var
  730.        PersonInfo: record
  731.           Name : String[30];
  732.           StreetAddress : String[30];
  733.           City : String[20];
  734.           State : String[2];
  735.           Zip : String[9];
  736.           Education: record
  737.             HiSchool : Boolean;
  738.             Bachelors : Boolean;
  739.             Masters : Boolean;
  740.             PhDLevel : Boolean;
  741.           end;
  742.        end;
  743.  
  744. Such nested records are accessed by referencing each component of the record,
  745. as,
  746.  
  747.      PersonInfo.Education.HiSchool := True;
  748.      PersonInfo.Education.Bachelors := True;                                   
  749.      
  750. For compatibility with other implementations of the Pascal langauge, the
  751. keyword packed may appear before the record keyword.  Turbo Pascal
  752. automatically packs all record structures so the keyword serves no purpose for
  753. Turbo Pascal programs.
  754.  
  755.  
  756. The With Statement
  757.      The use of long record names, or many nested record declarations, could
  758. develop into quite a typing chore.  Pascal provides the with statement to
  759. abbreviate access to the record components.  Here is an example of the with
  760. statement:
  761.  
  762.      with PersonInfo do
  763.      begin
  764.        Name := 'Sam Bedford';
  765.        Zip := '98327-7463';
  766.      end;
  767.  
  768. When there are multiple levels of record declarations, as in the example
  769. specifying education, above, the with statement may nest the components, such
  770. as,
  771.  
  772.      with PersonInfo.Education do
  773.      begin
  774.        HiSchool := True;
  775.        Bachelors := True;
  776.      end;
  777.  
  778. Pascal also allows the above with statement to be written variously as,
  779.  
  780.      with PersonInfo, Education do ...
  781.  
  782. and
  783.  
  784.      with PersonInfo do
  785.        with Education do ...
  786.  
  787. Later in this chapter, the use of pointers that point to records is explained. 
  788. You can similarly use the with statement in conjunction with a record pointer. 
  789. For example, if PPersonInfo is a variable that points to a PersonInfo record,
  790. the with statement may be written as,
  791.  
  792.      with PPersonInfo^ do
  793.      begin
  794.        Name := 'Sam Bedford';
  795.        Zip := '98327-7463';
  796.      end;
  797.  
  798. The use of pointers is explain detail in the section titled Pointer Types.
  799.        
  800. Important notes: Scoping rules and use of the with statement
  801.      Variables defined within a record are defined within the scope of the
  802. record declaration.  Since record variables must be prefaced with the record
  803. name (or nested inside a with statement), it is acceptable to have variables
  804. defined as in this example,
  805.  
  806.      var
  807.        X : Integer;
  808.        Point : record
  809.           X : Integer;
  810.           Y : Integer;
  811.        end;
  812.  
  813. because the variable X and the record component Point.X are uniquely specified.
  814.      If the record name used in the with statement is an array, then the index
  815. should not be changed within the scope of the with statement.  If PersonInfo is
  816. an array, then the statement,
  817.  
  818.      with PersonInfo[Index] do
  819.      begin
  820.        ...
  821.        Index := Index + 1;
  822.      end;
  823.  
  824. is not permitted.  To execute these statements properly, write,
  825.  
  826.      For Index := 1 to MaxRecords do
  827.        with PersonInfo[Index] do
  828.        ...
  829.  
  830. The with statement is also used with pointer variables, and such usage is
  831. described in the section on the use of pointers, below.
  832.  
  833.  
  834. Record Types
  835.      Type definitions are frequently equated to record structure definitions
  836. for ease of use, for passing records structures as procedure parameters, and
  837. especially when using pointers.  A type identifier is assigned a record
  838. structure as in this example to create a type identifier TPersonInfo:
  839.  
  840.      type
  841.        TPersonInfo = record
  842.           Name : String[30];
  843.           StreetAddress : String[30];
  844.           City : String[20];
  845.           State : String[2];
  846.           Zip : String[9];
  847.        end;
  848.  
  849. A variable can then be declared as:
  850.  
  851.      var
  852.        PersonInfo: TPersonInfo;
  853.  
  854. The components of PersonInfo are then accessed as in any other record
  855. structure.  The use of record structures and record types is further detailed
  856. in sections The Pointer Type and Procedures and Functions.
  857.  
  858.  
  859. Case-variant records
  860.      Pascal provides a special record construct called a case-variant record. 
  861. Case-variant records use multiple variable names to access the same memory
  862. space.  The case-variant record is defined using the case keyword (which has no
  863. real relationship to the case conditional statement described later in this
  864. chapter).  The case-variant part of a record must appear at the end of the
  865. record declaration, after all non-variant portions of the record have been
  866. declared.
  867.      Here's a modified example of the PersonInfo record, now containing a
  868. variant section to store an employer or school name:
  869.  
  870.      var
  871.        PersonInfo = record
  872.           Name : String[30];
  873.           StreetAddress : String[30];
  874.           City : String[20];
  875.           State : String[2];
  876.           Zip : String[9];
  877.           case Employed : Boolean of
  878.             True : ( EmployerName : String[30] );
  879.             False : ( SchoolName : String[30] );
  880.        end;
  881.  
  882.      Employed is a new Boolean type component of the record (although its value
  883. is irrelevant in terms of using the EmployerName or SchoolName fields). 
  884. Employed is the tag field of the case-variant part of the record.  Two
  885. alternate fields, EmployerName and SchoolName are defined.  Note the use of
  886. parenthesis around the variant field's definition.
  887.      The case portion of the record does not have a matching end statement, as
  888. is used in the conditional statement form of the case statement.  The end
  889. keyword that matches the record keyword terminates both the record and the
  890. case-variant.
  891.      If the person whose information is stored in this record is employed, then
  892. Employed is set to True, and the employer's name is stored in
  893. PersonInfo.EmployerName; otherwise, assuming that this person is in school, 
  894. the school name is stored in PersonInfo.SchoolName.  EmployerName and
  895. SchoolName occupy the same location in memory.  As a result, in this example,
  896. if you write,
  897.  
  898.      PersonInfo.EmployerName := 'George Smith, Inc';
  899.  
  900. and then write,
  901.  
  902.      Writeln(PersonInfo.SchoolName);
  903.  
  904. you will see,
  905.  
  906.      George Smith, Inc
  907.  
  908. printed on the display because EmployerName and SchoolName, in this example, 
  909. occupy the same memory locations.
  910.      In a more generalized sense, case-variant records are often used when
  911. storing information records, where much of the information is the same for each
  912. record, but depending upon each individual record. some data may be different. 
  913.      Each case in the variant record is matched to at least one constant value
  914. (on the left hand side of the colon ":").  Its not necessary that these
  915. constant values bear any relation to another field or identifier.  For
  916. instance, in Turbo Pascal's Turbo Vision programming environment, the TEvent
  917. record contains a variant item called evKeyDown (which is a constant).  This is
  918. defined as,
  919.  
  920.      evKeyDown: ( 
  921.        case Integer of
  922.           0: (KeyCode : Word);
  923.           1: (CharCode : Char;
  924.             ScanCode : Byte ));
  925.      evMessage: (
  926.        ...
  927.  
  928. (There is no end to match the case keyword because the next variant evMessage
  929. is placed immediately after the evKeyDown instance.)
  930.      In this example, the Integer tag field is used merely to define the
  931. identifiers KeyCode, CharCode and ScanCode.  This format is used to access the
  932. upper and lower bytes of the KeyCode word as char and byte values,
  933. respectively.
  934.      While there can only be a single case-variant component within a record,
  935. it is possible to nest the case-variant declarations to create as many
  936. case-variant fields as are needed.  For example, this record contains two
  937. case-variant records.
  938.  
  939.      var
  940.        PersonInfo : record
  941.           Name : String;
  942.           case Word of
  943.             0: (A : Integer);
  944.             1: (B : Integer);
  945.             2: (
  946.                case Word of
  947.                  0: (C : Integer);
  948.                  1: (D : Integer);
  949.                )
  950.        end; { PersonInfo record }
  951.  
  952.  
  953. File Types
  954.      Files are implemented in Turbo Pascal with a File type declaration and a
  955. variety of library procedures and functions, for opening, closing, reading,
  956. writing and performing random access.  File usage is described in the section
  957. at the end of this chapter, titled File Operations.
  958.  
  959.  
  960. Typed Constants:  Pre-initialized variables
  961.      Typed constants provide a way to declare a variable that is
  962. pre-initialized.  For example,
  963.  
  964.      Const
  965.        TotalLines : Integer = 0;
  966.        FileName : String[14] = 'NONAME.TXT';
  967.        Minimum : Word = 0;
  968.        Maximum : Word = 50;
  969.  
  970. In this form, the constant identifier defines a variable that is given an
  971. initial value at the start of a program.  Unlike regular constants, you can
  972. assign a new value to such identifiers during program execution.  The purpose
  973. of typed constants is to provide for initialized variable declarations.
  974.      Because typed constants are treated just like variables, typed constants
  975. are not equivalent to regular constants.  For example, if Minimum and Maximum
  976. are defined as above, then writing,
  977.  
  978.      var
  979.        Lines : Array[Minimum..Maximum] of String[80];
  980.  
  981. is invalid because Minimum and Maximum are initialized typed constants, not
  982. true constants.
  983.      For String typed constants, you must declare a maximum string length.  The
  984. maximum length, as shown in the example above, may be longer than the initial
  985. string value.
  986.      All typed constants are initialized at the beginning of the program's
  987. execution, including locally declared typed constants within procedures and
  988. functions.  As a result, locally defined typed constants are initialized only
  989. once - not each time that the procedure or function is invoked.  Listing 3.2
  990. shows other typed constants and how to initialize complex structures such as
  991. arrays of records.
  992.  
  993.  
  994. Listing 3.2.  A code fragment that uses typed constants.  This is not a
  995. complete program.
  996.    1  {TYPED.PAS}
  997.    2  
  998.    3  type
  999.    4    TDataRecord = record
  1000.    5                    Name        : String[20];
  1001.    6                    PhoneNumber : String[14];
  1002.    7                    Age         : Integer;
  1003.    8                  end;
  1004.    9  
  1005.   10  
  1006.   11  const
  1007.   12  
  1008.   13    { Initializes a typed constant record }
  1009.   14    SampleRecord : TDataRecord =
  1010.   15                    (Name : 'Ed'; PhoneNumber : '555-1212'; Age : 32 );
  1011.   16  
  1012.   17    { Initializes a typed constant array }
  1013.   18    SampleArray : Array [1..5] of Integer = (10, 20, 30, 40, 50);
  1014.   19  
  1015.   20    { Initializes a typed constant set }
  1016.   21    SampleSet : Set of Byte = [1, 100, 200];
  1017.   22  
  1018.   23  
  1019.   24    { Initializes a typed constant array of records }
  1020.   25    DataRecords : Array[0..4] of TDataRecord
  1021.   26  
  1022.   27    = ( (Name : 'George'; PhoneNumber : '262-1234'; Age : 10 ),
  1023.   28     (Name : 'John'  ; PhoneNumber : '262-1235'; Age : 20 ),
  1024.   29     (Name : 'Lisa'  ; PhoneNumber : '262-1236'; Age : 22 ),
  1025.   30      (Name : 'Marcia'; PhoneNumber : '262-1237'; Age : 30 ),
  1026.   31     (Name : 'Gwen'  ; PhoneNumber : '262-1238'; Age : 4 ) );
  1027.  
  1028.  
  1029. Important note:  Using typed-constants to create static local variables
  1030.      If you have programmed in C, you may recognize typed-constants as similar
  1031. to C's local static variables.  Like C, you can use locally defined typed
  1032. constants in a manner similar to C's static variables.  Normally, a local
  1033. variable defined inside a procedure or function in Turbo Pascal (or C) does not
  1034. retain its value between calls to the procedure or function.  Each time you
  1035. enter a procedure or function, you must reinitialize the local variable.   
  1036. However, sometimes a procedure may wish to retain information for future
  1037. reference.  While such values could be placed in a global variable, you can
  1038. provide better modularity by keeping the definition within the procedure where
  1039. the value is used.  By declaring the variable as a local typed constant, the
  1040. contents of the variable remain unchanged between calls to the procedure or
  1041. function.
  1042.  
  1043.  
  1044. The Pointer Type
  1045.      A pointer type is a variable whose contents point to some other location
  1046. in memory.  Pointers are used to access dynamically allocated variable types. 
  1047. Variables declared with var definition statements are static variables, meaning
  1048. that they are allocated at the start of a program (or procedure or function)
  1049. and remain allocated until the program (or procedure or function) terminates. 
  1050. Adynamic variable is one that is created during program execution (usually with
  1051. the New procedure) and remains allocated until explicitly thrown away using the
  1052. Dispose procedure.  
  1053.  
  1054.  
  1055. Defining and Allocating a Pointer
  1056.      New allocates a dynamic variable in a program's heap memory area, an area
  1057. reserved for all types of dynamic memory allocations.  (Other program memory
  1058. areas include the the program's code space and the stack, a memory structure
  1059. for keeping track of procedure and function calls, for allocating space to
  1060. local variables.)  A dynamic variable does not exist in any explicit variable
  1061. declaration.  Instead, New allocates memory for the variable within the heap
  1062. memory area and sets its variable parameter to the memory address of the
  1063. allocation.  A variable type called a pointer is defined to accept the memory
  1064. address.
  1065.      A pointer variable (that is, a variable of the pointer type) is defined
  1066. thusly:
  1067.  
  1068.      var
  1069.        PointsToString : ^String;
  1070.  
  1071. which declares PointsToString to hold a pointer to a String.  The value of
  1072. PointsToString is undefined, until it is given a value by calling New or by
  1073. equating to another pointer.  A special value, nil, is reserved for indicating
  1074. a pointer that does not currently point to anything (hence, the nil pointer).
  1075.      Memory space is dynamically allocated by calling New like this:
  1076.  
  1077.        New( PointsToString );
  1078.  
  1079. New takes the pointer type as its parameter and allocates sufficient memory
  1080. from the heap to store the type of data that PointsToString points to, in this
  1081. case a default 255 byte long string, plus a length byte.  PointsToString is
  1082. gets the value of the memory address where the string is allocated.
  1083.      (A special form of the New function is used in object-oriented
  1084. programming.  This format is described in Chapter 4, "Object Oriented
  1085. Programming", in the Borland Pascal Developer's Guide).
  1086.  
  1087.  
  1088. Using a Pointer
  1089.      To reference the data pointed to by PointsToString, use the circumflex
  1090. character ^, denoting "points to", as,
  1091.  
  1092.      PointsToString^ := 'This is a sample pointer to a string';
  1093.  
  1094. If you directly reference PointsToString, you are accessing the memory address
  1095. stored in PointsToString.  Use the circumflex ^ character to access what the
  1096. pointer is pointing at.  You can use the pointer variable like any other
  1097. variable.  Some examples:
  1098.  
  1099.      procedure WriteAString( S : String );
  1100.      begin
  1101.        writeln( S );
  1102.      end;
  1103.      ...
  1104.      WriteAString( PointsToString^ );
  1105.      ...
  1106.      for I := 1 to Length(PointsToString^) do
  1107.        write( PointsToString^[I] );
  1108.  
  1109.  
  1110. Disposing of a Dynamic variable
  1111.      Memory allocated with New remains allocated until explicitly disgarded
  1112. with Dispose.  Once a memory allocation has been disposed it can be reused
  1113. again by other program functions.
  1114.      To dispose of a dynamically allocated variable, pass the pointer to the
  1115. Dispose procedure, like this:
  1116.  
  1117.      New ( PointsToString );
  1118.      ...
  1119.      Dispose( PointsToString );
  1120.  
  1121. Note that the pointer address is passed to the Dispose procedure, not what the
  1122. pointer points to (unless of course, the pointer points to another pointer and
  1123. you are disposing of that pointer).  Hence, do not include the circumflex ^
  1124. "points to" notation on this parameter.
  1125.      (A special form of Dispose is used in object oriented programming and is
  1126. described in Chapter 4, "Object Oriented Programming", in the Borland Pascal
  1127. Developer's Guide).  Related procedures are GetMem and FreeMem and Mark and
  1128. Release, described later in this chapter).
  1129.  
  1130. Important Note:  Common problems when using pointers
  1131.      When working with pointers, the most common errors are failure to
  1132. initialize a pointer before use, and erroneously using a pointer after the
  1133. dynamically allocated variable it points to has been disgarded.  Another common
  1134. error is allocating a variable within a procedure or function and never calling
  1135. Dispose to free the memory.  If the procedure is called often, the program will
  1136. soon run out of memory and halt execution.
  1137.      To play it safe, always explicitly initialize pointer values to nil or to
  1138. an actual memory allocation, in order to avoid using a potentially random
  1139. memory reference.
  1140.      Always dispose of dynamic variables when they are no longer needed by
  1141. calling the Dispose procedure.
  1142.      Insure that once a dynamic allocation is disgarded with the Dispose
  1143. procedure that the now invalid memory pointer is no longer used.  Dispose
  1144. disgards the allocated heap memory but does not change the address stored in
  1145. the pointer variable.  As a result, you may inadvertently continue to use a
  1146. disposed pointer reference.  To play it safe and to help in subsequently
  1147. debugging your program, after calling Dispose, you may wish to assign nil to
  1148. the pointer.
  1149.  
  1150.  
  1151. The Use of Mark and Release Procedures
  1152.      When several pointers are allocated using the New procedure, memory blocks
  1153. are allocated one after the other, in sequence.  For example,
  1154.  
  1155.      New( P1 );
  1156.      New( P2 );
  1157.      New( P3 );
  1158.      New( P4 );
  1159.      New( P5 );
  1160.  
  1161. will (at least initially) allocate P1 through P5 so that they occupy sequential
  1162. blocks of memory (See Figure 3.3).
  1163.  
  1164. ***03tpr03.pcx***
  1165. Figure 3.3.  An illustration showing how several items are allocated in
  1166. sequential blocks of memory.
  1167.  
  1168.      Normally, these variable allocations are disposed of by calling the
  1169. Dispose procedure.  An alternate disposal method uses the Mark and Release
  1170. procedures.  When called, Mark saves the location within the heap memory area
  1171. of the next variable allocation.  Later, by calling Release, the heap memory is
  1172. reset to its allocation at the time Mark was called.  For example,
  1173.  
  1174.      New( P1 );
  1175.      New( P2 );
  1176.      Mark (P);
  1177.      New( P3 );
  1178.      New( P4 );
  1179.      New( P5 );
  1180.  
  1181. saves the location in variable P, where P can be of any pointer type, including
  1182. an untyped pointer declared as,
  1183.  
  1184.      var
  1185.        P : Pointer;
  1186.  
  1187. When the statement,
  1188.  
  1189.      Release( P );
  1190.  
  1191. is subsequently executed, the heap allocation is reset to its position prior to
  1192. the allocation of P3, P4 and P5 such that calling Release is equivalent to
  1193. individually disposing of P3, P4 and P5.  Release effectively frees up all
  1194. memory allocated since the matching Mark procedure call.
  1195.  
  1196. Important Note:  Cautions concerning the use of Mark and Release
  1197.      Mark and Release should only be used for programs that deallocate dynamic
  1198. variables in exactly the reverse order of their allocation.  In such a case,
  1199. the use of Mark and Release is more efficient than using Dispose.
  1200.      However, if variables are randomly allocated and disposed, then Mark and
  1201. Release should be used with caution, or not used at all.  When the Dispose
  1202. procedure removes a variable allocation, it maintains a list of free memory
  1203. space.  The Release procedure eliminates this free list and can cause the heap
  1204. memory manager to lose track of memory blocks that have already been freed
  1205. using Dispose.  For example, in this code section,
  1206.  
  1207.      New( P1 );
  1208.      New( P2 );
  1209.      Mark (P);
  1210.      New( P3 );
  1211.      New( P4 );
  1212.      New( P5 );
  1213.      Dipose (P1);
  1214.  
  1215. when Dispose (P1) is executed, a free block appears within the heap.  However,
  1216. if you now call Release(P), the free list that keeps track of the free block
  1217. previously pointed to by P1 is eliminated and that free memory can no longer be
  1218. recovered.
  1219.  
  1220.  
  1221. The Use of GetMem and FreeMem procedures
  1222.      Turbo Pascal allows the program to dynamically allocate arbitrarily sized
  1223. blocks of memory, up to a maximum of 65,521 bytes in size.  This memory is
  1224. allocated with the GetMem procedure, passing to it a pointer of any type, and
  1225. the size of the requested memory block.  For example, to dynamically allocate
  1226. an array of the char data type, you could use the example code in
  1227. Listing 3.3.
  1228.  
  1229. Listing 3.3.  Demonstration of how to dynamically allocate a large array of
  1230. characters.
  1231.  
  1232. program DemoGetMem;
  1233. type
  1234.   PCharArray = ^CharArray;
  1235.   CharArray = array [0..19999] of char;
  1236. var
  1237.   TextArray : PCharArray;
  1238.   I : Integer;
  1239. begin
  1240.   GetMem( TextArray, 20000 );
  1241.   for I := 0 to 19999 do
  1242.      TextArray^[I] := ' ';
  1243. end.
  1244.  
  1245.      Depending upon the amount of memory actually needed, you can use GetMem to
  1246. allocate a dynamically sized TextArray.  You don't need to allocate the full
  1247. 20,000 bytes; you could allocate a smaller value if that is all that is needed.
  1248.      Dynamic variables allocated with GetMem should be disposed of by calling
  1249. FreeMem, again passing to FreeMem the pointer variable and the actual memory
  1250. block sized allocated by GetMem.  For example,
  1251.  
  1252.      FreeMem ( TextArray, 20000 );
  1253.  
  1254. New and GetMem, and Dispose and FreeMem may be freely intermixed as they
  1255. internally use the same memory heap allocation mechansim.  However, the
  1256. cautions that apply to mixing calls to Dispose with Mark and Release also apply
  1257. to using Mark and Release with FreeMem.
  1258.  
  1259.  
  1260. Pointers and Memory Management
  1261.      When dynamically allocating memory space for a new variable, the heap
  1262. memory area may run out of available memory.  By default this results in a
  1263. program run-time error,
  1264.  
  1265.      Error 203: Heap Overflow error
  1266.  
  1267. causing the program to terminate execution.
  1268.      Turbo Pascal programs can intercept the out of memory condition using the
  1269. following programming trick.  The global system variable HeapError points to a
  1270. function that is called whenever a heap error occurs.  By setting HeapError to
  1271. point to your own function, your program can take its own action to handle the
  1272. out of memory condition and prevent a program terminating run-time error from
  1273. occurring.
  1274.      To use HeapError, define a function similar to this,
  1275.  
  1276.      function HeapErrorCondition ( Size : Word ): Integer; far;
  1277.  
  1278. and set HeapError as,
  1279.  
  1280.      HeapError := @HeapErrorCondition;
  1281.  
  1282. Also, see  The Address-of @ Operator, below.
  1283.      During program execution, if the heap runs low on memory and calls to New
  1284. or GetMem cannot be completed, the heap memory manager calls the function
  1285. pointed to by HeapError, passing to the heap error function the size of the
  1286. requested memory allocation that caused the heap manager to run out of memory.
  1287.      Within the HeapErrorCondition function, your program can display its own
  1288. error message, or optionally dispose of unneeded variables.  Upon completion,
  1289. the HeapErrorCondition function should return:
  1290.  
  1291.        0:  Means out of memory and causes a run-time error,
  1292.  
  1293.        1:  Means out of memory but causes New and GetMem to merely return a
  1294.        value of nil without generating a run-time error,
  1295.  
  1296.        2:  Means that memory was freed up and the New or GetMem routine can try
  1297.        again to allocate a memory block.  Note that this could result in
  1298.        another out of memory condition and a second call to HeapErrorCondition.
  1299.  
  1300.  
  1301. Pointer Relational Operators
  1302.      The only comparisons that can be made using pointer values directly are:
  1303.  
  1304.        =: Compare two pointers to see if they point to the same location, as
  1305.        in,
  1306.                     if P1 = P2 then ...
  1307.  
  1308.        <>: Compare two pointers to see if they are different from one another,
  1309.        as in,
  1310.                     if  P1 <> P2 then ...
  1311.  
  1312. Turbo Pascal does not allow relative comparisons such as,
  1313.  
  1314.      if P1 < P2 then ...
  1315.  
  1316. since these operations make no sense when applied to pointers.
  1317.  
  1318.  
  1319. The Address-of operator @
  1320.      In addition to using New to allocate a pointer variable, you may also
  1321. assign a pointer to an already allocated pointer, or you can assign a pointer
  1322. to the address of an existing variable using the @ address-of operator.  For
  1323. example, given the definitions,
  1324.  
  1325.      var
  1326.        AString : String;
  1327.        PointsToString : ^String;
  1328.      ...
  1329.      AString := 'Hello, World!';
  1330.      PointsToString := @AString;
  1331.      Writeln( PointsToString^ );
  1332.  
  1333. displays,
  1334.  
  1335.      Hello, World!
  1336.  
  1337. The statement,
  1338.  
  1339.      PointsToString := @AString;
  1340.  
  1341. assigns the memory address of AString to PointsToString.  Hence,
  1342. PointsToString^ points to the contents of AString.
  1343.  
  1344.  
  1345. @ and Procedures and Functions
  1346.      When the @ address-of operator is placed before a procedure or function,
  1347. it returns the address of the procedure or function's entry point.  This form
  1348. is used for passing a procedure or function location to an assembly language
  1349. routine, or to save a pointer to a procedure.  For example, given
  1350.  
  1351.      var
  1352.        ProcPointer : Pointer;
  1353.  
  1354.      function Sum(A, B: Integer) : Integer;
  1355.      ...
  1356.      ProcPointer := @Sum;
  1357.  
  1358. assigns ProcPointer the address of function Sum.
  1359.      Listing 3.4 illustrates the use of the @ symbol for passing a pointer to a
  1360. procedure as a procedure parameter.  This example uses the TCollection
  1361. object-oriented library method ForEach, which takes as its only a parameter, a
  1362. pointer to a procedure.  ForEach is defined as,
  1363.  
  1364.      procedure ForEach (Action: Pointer);
  1365.  
  1366. ForEach calls the procedure parameter using code that resembles,
  1367.  
  1368.  
  1369. Listing 3.4.  A sample procedure that uses the @ address-of operator on a
  1370. procedure.
  1371.  
  1372. procedure PrintPhoneBook;
  1373.   procedure PrintEntry( OneEntry : PPersonInfo ); far;
  1374.   begin
  1375.      with  OneEntry^  do
  1376.      Writeln(Name,Address,City,State,Zip,Age);
  1377.   end; { PrintEntry }
  1378.  
  1379. begin
  1380.   PhoneBook^.ForEach( @PrintEntry );
  1381. end;
  1382.  
  1383.      
  1384. @ and Procedure Value parameters
  1385.      When the @ address-of operator is placed before a variable that is a
  1386. procedural value parameter, then this returns the address of the stack location
  1387. containing the parameter's value.  See Procedure P in listting 3.5 for an
  1388. illustration of building a pointer reference to a value parameter.
  1389.  
  1390.  
  1391. @ and Procedure Variable parameters
  1392.      The use of @ on a procedure variable parameter produces the address of the
  1393. formal variable parameter passed to the procedure.  In other words, the pointer
  1394. returned by the @ address-of operator, points to the variable that was passed
  1395. to the procedure as a parameter.  Procedure Q in Listing 3.5 illustrates.
  1396.  
  1397. Listing 3.5.  Sample code that uses the @ address-of operator on procedure
  1398. pass-by-value and pass-by-address (or var) parameters.
  1399.  
  1400. program DemoAddressOf;
  1401. var
  1402.   AString : String;
  1403.   PointsToString : ^String;
  1404.  
  1405. procedure P ( S : String );
  1406. var
  1407.   PS : ^String;
  1408. begin
  1409.   PS := @S;
  1410.   Writeln(PS^);
  1411. end;
  1412.  
  1413. procedure Q ( var S : String );
  1414. var
  1415.   PS : ^String;
  1416. begin
  1417.   PS := @S;
  1418.   Writeln ( PS^ );
  1419.   PS^ := 'Goodbye!';
  1420. end;
  1421.  
  1422. begin
  1423.   AString := 'Hello, World!';
  1424.   P( AString );
  1425.   Q( AString );
  1426.   Writeln( AString );
  1427.   Readln;
  1428. end.
  1429.  
  1430.  
  1431. Summary of Pointer Operations
  1432.      A pointer is defined in a var or type definition, by prefacing the data
  1433. type that is pointed to, with a circumflex ^ character.
  1434.  
  1435. type
  1436.      PInteger = ^Integer;
  1437. var
  1438.      PointerToInteger : ^Integer;  { These two are 
  1439.                                         effectively equivalent }
  1440.      IntegerPointer : PInteger;
  1441.  
  1442.      A dynamic variable is allocated by calling New ( pointer-type or
  1443. pointer-variable ), which returns a memory address or pointer to the memory
  1444. location where the variable was allocated.  Note that the parameter to New may
  1445. be either the pointer itself, or the data type:
  1446.  
  1447.      PointerToInteger := New ( PointerToInteger );
  1448.      IntegerPointer := New ( PInteger );
  1449.  
  1450.      A pointer references the dynamic variable by appending the circumflex ^
  1451. character, so that,
  1452.  
  1453.      IntegerPointer^ := 12;
  1454.  
  1455. assigns the value 12 to memory location that IntegerPointer points to.
  1456.      All dynamic variables must be disgarded by calling the Dispose procedure,
  1457. passing to it the pointer to dispose of:
  1458.  
  1459.      Dispose( IntegerPointer );
  1460.  
  1461.